#include "StdAfx.h"
#include "BM25Model.h"
#include "SearchManager.h"
#include "QueryManager.h"
#include "QueryTerm.h"
#include <algorithm>


const static double k1 = 1.4;
const static double k2 = 100.0;
const static double b = 0.5;


BM25Model::BM25Model(SearchManager * pSM, QueryManager * pQM, std::string outFile):RankingModel(pSM, pQM, outFile)
{
	m_ofs.open(outFile);
}


BM25Model::~BM25Model(void)
{	
	if(m_ofs.is_open() == true)
		m_ofs.close();
}

void BM25Model::RankingQuery(unsigned int queryIndex, unsigned int printCount )
{
	QueryTerm *pQueryTerm = m_pQueryManager->GetQueryTerm(queryIndex);	
	
	if( pQueryTerm == 0 )
		return ;

	// Get N : the number of Document
	DocumentManager *pDocumentManager = m_pSearchManager->GetDocumentManager();
	unsigned int N = pDocumentManager->GetDocumentNumber();

	// Get Query Term & Term Weight
	QueryTermMap queryTermMap = pQueryTerm->GetTermFrequency();
	//QueryWeightMap queryMultiply = pQueryTerm->GetMultiply();
	ScoreMap scoreMap;
	scoreMap.clear();

	docRanking.clear();

	for( QueryTermMap::iterator it = queryTermMap.begin(); it != queryTermMap.end(); ++it )
	{
		TermData termData;
		IndexData* pData = m_pSearchManager->FindIndexData(it->first, termData);
		
		// Get df
		unsigned int DF = termData.df;
		
		// Get AVDL
		unsigned int CL = pDocumentManager->GetCollectionLength();
		double AVDL = static_cast<double>(CL) / static_cast<double>(N);
		
		while( pData != 0 )
		{
			unsigned int docIndex = pData->documentIndex;

			// Get DL
			unsigned int DL = pDocumentManager->GetDocumentLength(docIndex);
			double K = k1 * ( ( 1-b ) + b* ( DL / AVDL ) );
#ifdef TUNING_FREQUENCY_LIMIT
			int tf = (pData->tf > 6)?6:pData->tf;
			int qf = (it->second > 6)?6:it->second;
#else
			int tf = pData->tf;
			int qf = it->second;
#endif // TUNING_FREQUENCY_LIMIT
			//int qf = it->second;
			//double score = log( ((N - DF + 0.5 ) / ( DF +0.5 ))) * ((k1 + 1.0) * pData->tf/ (K + pData->tf )) * ((k2 + 1.0 ) * it->second / (k2 + it->second) );
			double score = log( ((N - DF + 0.5 ) / ( DF +0.5 ))) * ((k1 + 1.0) * tf/ (K + tf )) * ((k2 + 1.0 ) * qf / (k2 + qf) );

			if( scoreMap.find(docIndex) == scoreMap.end() )
				scoreMap.insert(ScoreMap::value_type(docIndex, score) );
			else
				scoreMap[docIndex] += score;

			pData = m_pSearchManager->NextIndexData();
		}
	}	

	for ( ScoreMap::iterator iter = scoreMap.begin(); iter != scoreMap.end(); ++iter )
		docRanking.push_back( std::make_pair( iter->first, iter->second) );
		
	sort( docRanking.begin(), docRanking.end(), descending);

	this->DisplayResult(queryIndex, printCount);
	
}